package com.ucom.deadlock;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * @author tathagata
 * 
 */
public class Client implements Runnable {

	private Connection dbConnection;
	private String query;
	private PreparedStatement stmtUpdateListEntries;
	private long start, end, total;
	private int updateCount;
	private int waitTimeout;

	Client(String query, int waitTimeout) {

		this.query = query;
		this.waitTimeout = waitTimeout;

		try {
			Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
			dbConnection = DriverManager.getConnection(
					"jdbc:derby://localhost:1527/myDB", "cs480", "ucom");
			stmtUpdateListEntries = dbConnection.prepareStatement(query);
			
			System.out.println("Wait timeout:" + stmtUpdateListEntries.getQueryTimeout());
			stmtUpdateListEntries.setQueryTimeout(waitTimeout);
			System.out.println(Thread.currentThread().getName()
					+ "\tConnected to DB.\nTimeout = "
					+ stmtUpdateListEntries.getQueryTimeout());
			
		} catch (ClassNotFoundException cnfe) {
			System.out.println("Error in creating Database conncetion");
			System.out.println(cnfe.getMessage());

		} catch (SQLException sqle) {
			System.out.println("Error in creating Database conncetion");
			System.out.println(sqle.getMessage());
		}

		

	}

	public void run() {

		try {

			java.util.Date timestamp = new java.util.Date();

			System.out.println("\n\n\nThread name :" + Thread.currentThread().getName());
			System.out.println("`----- Starting transaction at :" + timestamp.getTime());
			System.out.println("`----- Query is :");
			System.out.println("`----- " + query);
			
			start = System.currentTimeMillis();
			updateCount = stmtUpdateListEntries.executeUpdate();
			end = System.currentTimeMillis();

			total = end - start;

			System.out
			.println(Thread.currentThread().getName()
					+ "-"
					+ Thread.currentThread().getId()
					+ " successfully updated : " + updateCount
					+ " records using " + query + "in " + total
					+ " milliseconds");

		} catch (SQLException se) {
			if (se.getSQLState().equals("40001")) {
				System.out.println("********** Deadlock timeout: **********");

				end = System.currentTimeMillis();
				total = end - start;

				System.out.println("\n******************************************\n");
				System.out.println("\t\t"+Thread.currentThread().getName());
				System.out.println("\n******************************************\n" 
						+ ": Transaction aborted after executing for: " + "\t"
						+ total
						+ " seconds");
						
				System.out.println("Number of rows updated = " + updateCount);
				
				System.out.println("\n\n");
			} else if (se.getSQLState().equals("40XL1")
					|| se.getSQLState().equals("40XL2")) {
				System.out.println("*********** Lockwait timeout: **********");


				System.out.println("\n******************************************\n");
				System.out.println("\t\t"+Thread.currentThread().getName());
				System.out.println("\n******************************************\n" 
						+ ": Transaction aborted after executing for: " + "\t"
						+ total
						+ " seconds");
						
				System.out.println("Number of rows updated = " + updateCount);
				
				System.out.println("\n\n");
			} else {
				end = System.currentTimeMillis();
				total = end - start;
				System.out.println("\n******************************************\n");
				System.out.println("\t\t"+Thread.currentThread().getName());
				System.out.println("\n******************************************\n" 
						+ " Transaction aborted after executing for: " + "\t"
						+ total
						+ " seconds");
				System.out.println("Number of rows updated = " + updateCount);
				System.out.println("Error code: " + se.getErrorCode());
				System.out.println("Error Message: " + se.getMessage());
				System.out.println("Error State: " + se.getSQLState() + "\t" + se.getCause());
			}
		} catch (Exception e) {
			e.getMessage();
			e.printStackTrace();
		} finally {
			try {
				stmtUpdateListEntries.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}

			try {
				dbConnection.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
	}
}
